﻿using EOH.IoTCard.CMCC.Res;

using NewLife;
using NewLife.Serialization;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace EOH.IoTCard.CMCC
{
    public class CmccRequest<TResponse> : IRequest<TResponse>
    {
        public virtual string? Url { get; }
        public virtual HttpMethod Method => HttpMethod.Get;
        public TResponse? ConvertResponse(string content) { if (string.IsNullOrWhiteSpace(content)) { return default; } return content.ToJsonEntity<TResponse>(); }
    }
    public class CmccRequest<TModel, TResponse> : CmccRequest<TResponse>, IRequest<TModel, TResponse>
    {
        public TModel? Model { get; set; }
    }
    public class CmccResponse
    {
        public string? status { get; set; }
        public string? message { get; set; }

        public bool IsSuccess => "0".EqualIgnoreCase(status);
    }
    public class CmccResponse<TResponse> : CmccResponse
    {
        public TResponse result { get; set; }
    }
    /// <inheritdoc/>
    public class CmccService : IService
    {
        #region 属性
        readonly IHttpClientFactory? _HttpClientFactory;
        readonly CmccOptions? _CmccOptions;
        static string _HttpClientFactoryName = typeof(CmccService).FullName;
        int _TransId;
        /// <summary>
        /// 事务编码，由物联卡集团客户按照相应规则自
        /// 主生成。生成规则：
        /// APPID+YYYYMMDDHHMISS+8 位数字序列（此
        /// 序列由集团客户自主生成，比如从 00000001
        /// 开始递增等等），transid 样例：
        /// 10005999927000000620141016153030
        /// 80000001
        /// </summary>
        string TransId
        {
            get
            {
                Interlocked.Increment(ref _TransId);
                if (_TransId > 99999999) { _TransId = 0; Interlocked.Increment(ref _TransId); }
                var text = $"{_TransId}".PadLeft(8, '0');
                return $"{_CmccOptions.AppId}{DateTime.Now:yyyyMMddHHmmss}{text}";
            }
        }
        GetTokenResponse? Token;
        readonly object _Lock = new();
        #endregion

        #region 构造函数
        /// <summary>构造函数</summary>
        public CmccService(IHttpClientFactory? HttpClientFactory, CmccOptions? options)
        {
            _HttpClientFactory = HttpClientFactory;
            _CmccOptions = options;
        }
        #endregion
        /// <inheritdoc/>
        public Task<TResponse> Execute<TResponse>(IRequest<TResponse> request) { lock (_Lock) { CheckTokenValid(); } return Send(request); }
        /// <inheritdoc/>
        public Task<TResponse> Execute<TModel, TResponse>(IRequest<TModel, TResponse> request) { lock (_Lock) { CheckTokenValid(); } return Send(request, request.Model); }

        async Task<TResponse> Send<TResponse>(IRequest<TResponse> request, object model = null!)
        {
            try
            {
                using var client = _HttpClientFactory?.CreateClient(_HttpClientFactoryName);
                var param = BuildParams(model);
                param = string.IsNullOrWhiteSpace(param) ? string.Empty : $"&{param}";
                using var upiotRequest = new HttpRequestMessage(request.Method, $"{request.Url}?transid={TransId}{param}");
                using var response = await client.SendAsync(upiotRequest);
                response.EnsureSuccessStatusCode();
                var res = await response.Content.ReadAsStringAsync();
                var data = request.ConvertResponse(res);
                if (data is CmccResponse r && r.status.EqualIgnoreCase("12021"))
                {
                    lock (_Lock)
                    {
                        Token = null;
                        CheckTokenValid();
                    }
                    data = await Send(request, model);
                }
                return data!;
            }
            catch (Exception) { throw; }
        }

        string BuildParams(object model = null)
        {
            if (model is null) { return string.Empty; }
            var dic = model?.ToDictionary();
            var param = dic?.Where(o => !string.IsNullOrWhiteSpace($"{o.Value}")).Select(o => $"{o.Key}={o.Value}").ToList();
            if (Token is not null && Token.IsTokenValid) { param.Add($"{nameof(Token.token)}={Token.token}"); }
            return string.Join("&", param);
        }

        void CheckTokenValid()
        {
            if (Token is null || !Token.IsTokenValid)
            {
                var request = new GetTokenRequest { Model = new GetTokenModel { appid = _CmccOptions.AppId, password = _CmccOptions.Password } };
                var data = Send(request, request.Model).Result;
                if (data == null || !data.IsSuccess) { throw new Exception($"{nameof(GetTokenRequest)}失败 {data?.ToJson()}"); }
                Token = data.result.FirstOrDefault();
            }
        }

    }
}
